package com.yboot.starter.mybatis.core.utils;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yboot.starter.api.core.annotation.Query;
import com.yboot.starter.api.core.annotation.QueryIgnore;
import com.yboot.starter.api.core.constant.LogicalRelation;
import com.yboot.starter.api.core.constant.QueryType;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

/**
 * QueryWrapper 助手
 *
 * @author yangcs
 * @date 2025/8/29
 */
@Slf4j
public class QueryWrapperHelper {

    /**
     * 构建 QueryWrapper
     *
     * @param query        查询条件
     * @param fields       查询条件字段列表
     * @param queryWrapper QueryWrapper
     * @param <Q>          查询条件数据类型
     * @param <R>          查询数据类型
     * @return QueryWrapper
     */
    public static <Q, R> QueryWrapper<R> build(Q query, List<Field> fields, QueryWrapper<R> queryWrapper) {
        // 没有查询条件，直接返回
        if (query == null) {
            return queryWrapper;
        }
        // 解析并拼接查询条件
        for (Field field : fields) {
            List<Consumer<QueryWrapper<R>>> consumers = buildWrapperConsumer(query, field);
            queryWrapper.and(CollUtil.isNotEmpty(consumers), q -> consumers.forEach(q::or));
        }
        return queryWrapper;
    }

    /**
     * 构建 QueryWrapper Consumer
     *
     * @param query 查询条件
     * @param field 查询条件字段
     * @param <Q>   查询条件数据类型
     * @param <R>   查询数据类型
     * @return QueryWrapper Consumer
     */
    private static <Q, R> List<Consumer<QueryWrapper<R>>> buildWrapperConsumer(Q query, Field field) {
        try {
            // 如果字段值为空，直接返回
            Object fieldValue = ReflectUtil.getFieldValue(query, field);
            if (ObjectUtil.isEmpty(fieldValue)) {
                return Collections.emptyList();
            }
            // 设置了 @QueryIgnore 注解，直接忽略
            QueryIgnore queryIgnoreAnnotation = AnnotationUtil.getAnnotation(field, QueryIgnore.class);
            if (queryIgnoreAnnotation != null) {
                return Collections.emptyList();
            }
            // 建议：数据库表列建议采用下划线连接法命名，程序变量建议采用驼峰法命名
            String fieldName = ReflectUtil.getFieldName(field);
            // 没有 @Query 注解，默认等值查询
            Query queryAnnotation = AnnotationUtil.getAnnotation(field, Query.class);
            if (queryAnnotation == null) {
                return Collections.singletonList(q -> q.eq(CharSequenceUtil.toUnderlineCase(fieldName), fieldValue));
            }
            // 解析单列查询
            QueryType queryType = queryAnnotation.type();
            String[] columns = queryAnnotation.columns();
            final int columnLength = ArrayUtil.length(columns);
            List<Consumer<QueryWrapper<R>>> consumers = new ArrayList<>(columnLength);
            if (columnLength <= 1) {
                String columnName = columnLength == 1 ? columns[0] : CharSequenceUtil.toUnderlineCase(fieldName);
                parse(queryType, columnName, fieldValue, consumers);
                return consumers;
            }
            // 解析多列查询
            LogicalRelation logicalRelation = queryAnnotation.logicalRelation();
            List<Consumer<QueryWrapper<R>>> columnConsumers = new ArrayList<>();
            for (String column : columns) {
                parse(queryType, column, fieldValue, columnConsumers);
            }

            if (logicalRelation == LogicalRelation.AND) {
                if (!columnConsumers.isEmpty()) {
                    consumers.add(q -> {
                        columnConsumers.get(0).accept(q);
                        columnConsumers.subList(1, columnConsumers.size()).forEach(q::and);
                    });
                }
            } else {
                consumers.addAll(columnConsumers);
            }
            return consumers;
        } catch (Exception e) {
            log.error("Build query wrapper occurred an error: {}. Query: {}, Field: {}.", e
                    .getMessage(), query, field, e);
        }
        return Collections.emptyList();
    }

    /**
     * 解析查询条件
     *
     * @param queryType  查询类型
     * @param columnName 列名
     * @param fieldValue 字段值
     * @param <R>        查询数据类型
     */
    private static <R> void parse(QueryType queryType,
                                  String columnName,
                                  Object fieldValue,
                                  List<Consumer<QueryWrapper<R>>> consumers) {
        switch (queryType) {
            case EQ: {
                consumers.add(q -> q.eq(columnName, fieldValue));
                break;
            }
            case NE: {
                consumers.add(q -> q.ne(columnName, fieldValue));
                break;
            }
            case GT: {
                consumers.add(q -> q.gt(columnName, fieldValue));
                break;
            }
            case GE: {
                consumers.add(q -> q.ge(columnName, fieldValue));
                break;
            }
            case LT: {
                consumers.add(q -> q.lt(columnName, fieldValue));
                break;
            }
            case LE: {
                consumers.add(q -> q.le(columnName, fieldValue));
                break;
            }
            case BETWEEN: {
                // 数组转集合
                List<Object> between = new ArrayList<>(ArrayUtil.isArray(fieldValue)
                        ? ListUtil.of((Object[]) fieldValue)
                        : (List<Object>) fieldValue);
                Assert.isFalse(between.size() != 2, "[{}] 必须是一个范围", columnName);
                consumers.add(q -> q.between(columnName, between.get(0), between.get(1)));
                break;
            }
            case LIKE: {
                consumers.add(q -> q.like(columnName, fieldValue));
                break;
            }
            case LIKE_LEFT: {
                consumers.add(q -> q.likeLeft(columnName, fieldValue));
                break;
            }
            case LIKE_RIGHT: {
                consumers.add(q -> q.likeRight(columnName, fieldValue));
                break;
            }
            case IN: {
                Assert.notNull(fieldValue, "[{}] 不能为空", columnName);
                consumers.add(q -> q.in(columnName, ArrayUtil.isArray(fieldValue)
                        ? ListUtil.of((Object[]) fieldValue)
                        : (Collection<Object>) fieldValue));
                break;
            }
            case NOT_IN: {
                Assert.notNull(fieldValue, "[{}] 不能为空", columnName);
                consumers.add(q -> q.notIn(columnName, ArrayUtil.isArray(fieldValue)
                        ? ListUtil.of((Object[]) fieldValue)
                        : (Collection<Object>) fieldValue));
                break;
            }
            case IS_NULL: {
                consumers.add(q -> q.isNull(columnName));
                break;
            }
            case IS_NOT_NULL: {
                consumers.add(q -> q.isNotNull(columnName));
                break;
            }
            default:
                throw new IllegalArgumentException(String.format("暂不支持 [%s] 查询类型", queryType));
        }
    }

}
